package other.edan.system.ehr;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.ScheduleJob;
import com.rkhd.platform.sdk.api.annotations.RequestMethod;
import com.rkhd.platform.sdk.api.annotations.RestApi;
import com.rkhd.platform.sdk.api.annotations.RestMapping;
import com.rkhd.platform.sdk.data.model.Department;
import com.rkhd.platform.sdk.data.model.SyncConfig__c;
import com.rkhd.platform.sdk.data.model.User;
import com.rkhd.platform.sdk.exception.AsyncTaskException;
import com.rkhd.platform.sdk.exception.CacheException;
import com.rkhd.platform.sdk.exception.ScriptBusinessException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.model.BatchOperateResult;
import com.rkhd.platform.sdk.model.OperateResult;
import com.rkhd.platform.sdk.model.QueryResult;
import com.rkhd.platform.sdk.model.XObject;
import com.rkhd.platform.sdk.param.ScheduleJobParam;
import com.rkhd.platform.sdk.service.FutureTaskService;
import com.rkhd.platform.sdk.service.XoqlService;
import com.rkhd.platform.sdk.task.FutureTask;
import org.apache.commons.lang.StringUtils;
import other.edan.system.client.EdanK3Utils;
import other.edan.system.utils.HCDateUtils;
import other.edan.system.utils.HCXObjectService;
import other.edan.system.utils.ResultBody;
import other.edan.system.utils.TfReturnMsgTools;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Description 同步EHR部门以及人员信息
 * @Author 黎炎松
 * 2024-06-19 13:53
 */
@RestApi(baseUrl = "/xsy/ehr")
public class SyncEHRDepartUser implements ScheduleJob, FutureTask {
    private static XoqlService xoqlService = XoqlService.instance();
    private static final Logger logger = LoggerFactory.getLogger();
    private static String reqToken;
    private static String LOGGER_MSG = "定时读取明基EHR部门、人员信息 ==> ";

    // 执行定时任务
    @Override
    public void execute(ScheduleJobParam scheduleJobParam) {
        logger.debug(LOGGER_MSG + " 执行定时任务开始");
        try {
            String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
            logger.info(LOGGER_MSG + "异步ID:" + messageId);
        } catch (Exception e) {
            logger.error(LOGGER_MSG + " ----- 发生异常：" + e.getMessage());
        }
    }

    // 执行异步函数
    @Override
    public void execute(String s) throws ScriptBusinessException {
        startSyncDepartData();
    }

    /**
     * 手动触发产品同步
     * @param
     * @return
     */
    @RestMapping(value = "/syncDepart", method = RequestMethod.GET)
    public String syncDepart() throws AsyncTaskException {
        logger.debug("手动触发部门同步");
        String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
        logger.info(LOGGER_MSG + "异步ID:" + messageId);
        return TfReturnMsgTools.getSuccessResult("Start synchronizing data");
    }


    public static void main(String[] args) throws Exception {
        HCXObjectService.isLocal  = true;
        reqToken = EdanK3Utils.getToken();
        //new SyncEHRDepartUser().startSyncDepartData();

        new SyncEHRDepartUser().startSyncDepartUserData("0108020202");
    }



    /**
     * 开始同步部门数据
     */
    public String startSyncDepartData() {
        try {
            logger.debug(LOGGER_MSG + "处理开始");

            // 获取系统中 code 为 0108 的部门数据
            String sql = "select id,entityType from department where departCode = '0108'";
            Department parentDepartment = HCXObjectService.queryOne(sql);
            logger.debug(LOGGER_MSG + " parentDepartment = " + parentDepartment);
            if (parentDepartment == null) {
                logger.debug(LOGGER_MSG + "系统中查询理邦部门(code:0108)数据异常");
                return TfReturnMsgTools.getSuccessResult("Abnormal data query in the system for the Libang department (code: 0108)");
            }

            // 从数据配置表中获取数据
            sql = "select id,lastSyncTime__c,syncAssistVal__c from syncConfig__c where syncKey__c = 'MJ_EHR'";
            SyncConfig__c syncConfig = HCXObjectService.queryOne(sql);
            logger.debug(LOGGER_MSG + " syncConfig = " + syncConfig);
            if (syncConfig == null) {
                logger.debug(LOGGER_MSG + " 数据配置信息不存在");
                return TfReturnMsgTools.getFailResult("Data configuration information does not exist");
            }

            // 同步时间
            String syncDate = HCDateUtils.dateToString(new Date(), HCDateUtils.FORMATTIME); // 同步时间

            // 设置参数
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("code", "0108");
            logger.debug(LOGGER_MSG + " paramsMap: " + paramsMap);

            // 发送请求获取数据
            reqToken = EdanK3Utils.getToken();
            ResultBody response = EdanK3Utils.sendGet(paramsMap, EdanK3Utils.GET_EHR_DEPART_URL, reqToken);
            if (!Objects.equals(response.getCode(), "200")) {
                logger.error(LOGGER_MSG + "查询明基部门数据异常:" + response.getMessage());
                return TfReturnMsgTools.getFailResult("Abnormal departmental data query:" + response.getMessage());
            }

            // 获取产品数据 判断是否有值
            JSONArray departResultArr = (JSONArray) response.getResult();
            logger.debug(LOGGER_MSG + "查询部门返回的数据: " + departResultArr.size());
            if (departResultArr.size() <= 0) {
                logger.debug(LOGGER_MSG + "暂无需要处理的部门数据");
                // 同步修改配置表
                syncConfig.setLastSyncTime__c(syncDate);
                syncConfig.setLastSyncCount__c(0L);
                HCXObjectService.update(syncConfig);
                return TfReturnMsgTools.getSuccessResult("There are no departments that need to be synchronized");
            }

            // 返回的数据只获取子部门
            Long parentId = parentDepartment.getId(); // 父级部门id
            JSONObject departObj = (JSONObject) departResultArr.get(0);
            List<JSONObject> departList = JSONObject.parseArray(departObj.getJSONArray("children").toJSONString(), JSONObject.class);
            logger.debug(LOGGER_MSG + "departList: " + departList.size());


            // 根据 code 获取系统中是否存在
            String departCodes = getDepartCodes(departList);
            System.out.println("departCodes = " + departCodes);
            sql = "select id,departName,departCode,entityType from department where departCode in (" + departCodes + ")";
            QueryResult<JSONObject> departQuery = xoqlService.query(sql, true);
            Map<String, List<JSONObject>> crmDepartMap = departQuery.getRecords().stream().collect(Collectors.groupingBy(e -> e.getString("departCode")));
            logger.debug(LOGGER_MSG + "crmDepartMap: " + crmDepartMap.size());


            // 新增、修改部门数据
            List<Department> upDepartList = new ArrayList<>();
            addOrUpDepart(parentId, departList, crmDepartMap, upDepartList);


            // 批量修改
            if (upDepartList.size() > 0) {
                logger.info(LOGGER_MSG + "修改的数据: " + upDepartList.size());
                BatchOperateResult batchOperateResult = HCXObjectService.updateBatch(upDepartList);
                if (batchOperateResult != null && !batchOperateResult.getSuccess()) {
                    logger.error(LOGGER_MSG + "批量修改异常: " + batchOperateResult.getErrorMessage());
                    return TfReturnMsgTools.getFailResult("Modify department exception:"  +batchOperateResult.getErrorMessage());
                }
            }

            // 同步当前部门下的人员信息
            startSyncDepartUserData(departCodes);

            // 更新同步配置
            syncConfig.setLastSyncTime__c(syncDate);
            //syncConfig.setLastSyncCount__c(Long.valueOf(departList.size()));
            OperateResult update = HCXObjectService.update(syncConfig);
            if (!update.getSuccess()) {
                logger.error(LOGGER_MSG + "更新同步配置异常");
                return TfReturnMsgTools.getFailResult("Update synchronization configuration exception");
            }

            logger.debug(LOGGER_MSG + "处理成功");
            return TfReturnMsgTools.getSuccessResult("Synchronization successful");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return TfReturnMsgTools.getFailResult("Synchronization exception:" + e.getMessage());
        }
    }

    /**
     * 开始同步部门下的人员数据
     * @param departCodes
     * @throws Exception
     */
    public void startSyncDepartUserData(String departCodes) throws Exception {
        try {
            logger.debug(LOGGER_MSG + "开始同步部门用户");

            // 获取理邦部门数据
            if (StringUtils.isBlank(departCodes)) {
                departCodes = "'010801','01080102','0108010201','0108010202','0108010203','0108010204','01080101','0108010101','0108010102'," +
                        "'0108010103','010802','01080204','01080203','01080201','0108020101','0108020102','0108020103','01080202','0108020201'," +
                        "'0108020202','0108020203','0108020204','0108020205','010803','01080313','01080312','01080306','0108030601','01080308'," +
                        "'0108030801','0108030802','0108030803','0108030804','0108030805','0108030806','01080309','0108030901'";
            }
            String sql = "select id,departName,departCode,entityType from department where departCode in (" + departCodes + ")";
            QueryResult<JSONObject> departQuery = xoqlService.query(sql, true);
            List<JSONObject> departRecords = departQuery.getRecords();
            logger.debug(LOGGER_MSG + "departRecords:" + departRecords.size());


            // 获取理邦部门下的所有人员数据
            String departIds = departRecords.stream().map(v -> v.getString("id")).collect(Collectors.joining(","));
            sql = "select id,ehrPersonId__c from user where personalEmail is not null and dimDepart in (" + departIds +  ")";
            QueryResult<JSONObject> departUserQuery = xoqlService.query(sql, true);
            Map<String, Long> crmDepartUserMap = departUserQuery.getRecords().stream().collect(Collectors.toMap(e -> e.getString("ehrPersonId__c"), e1 -> e1.getLong("id")));
            logger.debug(LOGGER_MSG + "crmDepartUserMap:" + crmDepartUserMap.size());

            // 根据部门获取对应的人员信息
            List<User> addUserList = new ArrayList<>();
            List<User> upUserList = new ArrayList<>();
            for (JSONObject departRecord : departRecords) {

                // 获取部门下的用户列表
                String departCode = departRecord.getString("departCode");
                Long departId = departRecord.getLong("id");
                List<JSONObject> deptUserList = getDepartUserListByCode(departCode);

                // 获取新增的用户数据
                for (JSONObject deptUser : deptUserList) {

                    String email = deptUser.getString("email");
                    // 离职、或者邮箱为空的用户不进行同步
                    if (Objects.equals(deptUser.getString("status"),"离职") || StringUtils.isBlank(email)) {
                        continue;
                    }

                    User user = new User();
                    user.setDimDepart(departId); // 部门
                    String personId = deptUser.getString("personId");
                    user.setEhrPersonId__c(personId); // 用户id

                    user.setGender(Objects.equals(deptUser.getString("gender"),"女") ? 2: 1); // 性别 1 男  2 女
                    user.setEmployeeCode(deptUser.getString("workNum")); // 工号
                    user.setExpertise(deptUser.getString("superiorWorkNum")); // 直属上级工号
                    user.setPositionName(deptUser.getString("position")); // 职位名称
                    email = email.trim().toLowerCase();
                    user.setPersonalEmail(email); // 邮箱

                    // 手机号码
                    String mobileNumber = deptUser.getString("mobileNumber");
                    if (isValidPhoneNumber(mobileNumber)) {
                        user.setChinaPhone__c(mobileNumber);
                    }

                    // 判断是否已经存在 存在则修改
                    if (crmDepartUserMap.containsKey(personId)) {
                        user.setId(crmDepartUserMap.get(personId));
                        upUserList.add(user);
                        continue;
                    }

                    user.setName(deptUser.getString("name")); // 姓名
                    user.setAttribute("accountType", 0); // 登录方式 0：邮箱 1: 手机号
                    //user.setStatus(Objects.equals(deptUser.getString("status"), "离职") ? -11 : 0); // 状态
                    user.setStatus(0); // 状态
                    user.setLanguageCode("zh"); // 地区
                    user.setTimezone("Asia/Shanghai"); // 时区
                    user.setLocal("CN"); // 区域
                    user.setCurrency("currencyUnit1"); // 币种
                    addUserList.add(user);
                }
            }

            logger.debug(LOGGER_MSG + "批量新增用户数据:" + addUserList.size());
            if (addUserList.size() > 0) {
                BatchOperateResult batchOperateResult = HCXObjectService.insertBatch(addUserList);
                if (batchOperateResult != null && !batchOperateResult.getSuccess()) {
                    logger.error(LOGGER_MSG + "批量新增用户异常数据:" + addUserList);
                    List<OperateResult> operateResults = batchOperateResult.getOperateResults();
                    for (OperateResult operateResult : operateResults) {
                        logger.error(LOGGER_MSG + "批量新增用户数据异常原因:" +  operateResult.getCode() + " => " + operateResult.getErrorMessage() + " => " + operateResult.getDataId());
                    }
                    logger.error(LOGGER_MSG + "批量新增用户数据异常:" + batchOperateResult.getErrorMessage());
                    //return;
                }
            }

            // 批量保存用户数据
            logger.debug(LOGGER_MSG + "批量保存用户数据:" + upUserList.size());
            if (upUserList.size() > 0) {
                BatchOperateResult batchUpOperateResult = HCXObjectService.updateBatch(upUserList);
                if (batchUpOperateResult != null && !batchUpOperateResult.getSuccess()) {
                    List<OperateResult> operateResults = batchUpOperateResult.getOperateResults();
                    operateResults = operateResults.stream().filter(v -> !v.getSuccess()).collect(Collectors.toList());
                    logger.debug(LOGGER_MSG + "批量保存用户异常数据数量:" + operateResults.size());
                    for (OperateResult operateResult : operateResults) {
                        if (!operateResult.getSuccess()) {
                            logger.error(LOGGER_MSG + "批量保存用户数据异常原因:" +  operateResult.getCode() + " => " + operateResult.getErrorMessage() + " => " + operateResult.getDataId());
                        }
                    }
                    logger.error(LOGGER_MSG + "批量保存用户数据异常:" + batchUpOperateResult.getErrorMessage());
                    return;
                }
            }

            logger.debug(LOGGER_MSG + "同步部门用户成功");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOGGER_MSG + "同步部门用户异常: " + e.getMessage());
        }
    }

    /**
     * 校验手机号是否正确
     * @param number
     * @return
     */
    public static boolean isValidPhoneNumber(String number) {
        // 中国大陆手机号码正则表达式
        String regex = "^1[3-9]\\d{9}$";
        return number.matches(regex);
    }

    /**
     * 根据code获取部门下的人员
     * @param code
     * @return
     */
    public List<JSONObject> getDepartUserListByCode(String code) throws CacheException {
        List<JSONObject> deptUserList = new ArrayList<>();

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("departmentCode", code);
        paramsMap.put("page", 1);
        paramsMap.put("pageSize", 500);
        //logger.debug(LOGGER_MSG + " paramsMap: " + paramsMap);

        // 发送请求获取数据
        ResultBody response = EdanK3Utils.sendGet(paramsMap, EdanK3Utils.GET_EHR_DEPART_USER_URL, reqToken);
        if (!Objects.equals(response.getCode(), "200")) {
            logger.error(LOGGER_MSG + "查询明基部门人员数据异常:" + response.getMessage());
            return deptUserList;
        }

        // 获取产品数据 判断是否有值
        JSONObject result = (JSONObject) response.getResult();
        deptUserList = JSONObject.parseArray(result.getJSONArray("hrAccountInfos").toJSONString(), JSONObject.class);
        logger.debug(LOGGER_MSG + "查询部门人员返回的数据: " + code + " => " + deptUserList.size());
        if (deptUserList.size() <= 0) {
            logger.debug(LOGGER_MSG + "暂无需要处理的部门人员数据");
            return deptUserList;
        }

        return deptUserList;
    }




    /**
     * 循序新增部门数据
     * @param departList
     * @param crmDepartMap
     * @param upDepartList
     */
    public void addOrUpDepart(Long parentId, List<JSONObject> departList, Map<String, List<JSONObject>> crmDepartMap, List<Department> upDepartList) {
        for (JSONObject jsonObject : departList) {
            String code = jsonObject.getString("code");

            // 处理新增的参数
            Department department = new Department();
            department.setDepartType(2);
            department.setDepartName(jsonObject.getString("name"));
            department.setDepartCode(code);
            department.setParentDepartId(parentId);

            // 判断系统中是否存在，存在则更新
            logger.debug(LOGGER_MSG + "department =" + department);
            Long departId = null;
            if (crmDepartMap.containsKey(code)) {
                departId = crmDepartMap.get(code).get(0).getLong("id");
                department.setId(departId);
                upDepartList.add(department);
            } else {
                // 新增操作 (首次初始化数据不多，单个新增，提供子级需要的父级id)
                OperateResult insert = HCXObjectService.insert(department);
                departId = insert.getDataId();
            }

            // 处理子级
            JSONArray children = jsonObject.getJSONArray("children");
            if (children != null && children.size() > 0) {
                List<JSONObject> childrenList = JSONObject.parseArray(children.toJSONString(), JSONObject.class);
                addOrUpDepart(departId, childrenList, crmDepartMap, upDepartList);
            }
        }
    }



    /**
     * 获取部门code
     * @param departList
     * @return
     */
    public String getDepartCodes(List<JSONObject> departList) {
        List<String> codeList = new ArrayList<>();
        getDepartCodeList(codeList, departList);
        return codeList.stream().map(v -> "'" + v + "'").collect(Collectors.joining(","));
    }

    public void getDepartCodeList(List<String> codeList, List<JSONObject> departList) {
        for (JSONObject jsonObject : departList) {
            codeList.add(jsonObject.getString("code"));
            JSONArray children = jsonObject.getJSONArray("children");
            if (children != null && children.size() > 0) {
                List<JSONObject> childrenList = JSONObject.parseArray(jsonObject.getJSONArray("children").toJSONString(), JSONObject.class);
                getDepartCodeList(codeList, childrenList);
            }
        }
    }

}
